package cn.stylefeng.guns.modular.api;

import cn.stylefeng.guns.api.core.util.JwtTokenUtil;
import cn.stylefeng.guns.base.consts.ConstantsContext;
import cn.stylefeng.guns.base.shiro.ShiroUser;
import cn.stylefeng.guns.config.redis.redis.util.Redishandler0;
import cn.stylefeng.guns.modular.business.common.Constants;
import cn.stylefeng.guns.modular.business.model.dto.AmountQueryCondition;
import cn.stylefeng.guns.modular.business.model.dto.BindingUserInfoDTO;
import cn.stylefeng.guns.modular.business.model.params.UserTeamParam;
import cn.stylefeng.guns.modular.business.model.result.AmountRecordResult;
import cn.stylefeng.guns.modular.business.model.result.BingingResultView;
import cn.stylefeng.guns.modular.business.model.result.MoneyLogResult;
import cn.stylefeng.guns.modular.business.service.AccountService;
import cn.stylefeng.guns.modular.business.service.MoneyLogService;
import cn.stylefeng.guns.modular.business.service.UserPropertyService;
import cn.stylefeng.guns.sms.core.enums.SmsTemplateCode;
import cn.stylefeng.guns.sys.core.shiro.ShiroKit;
import cn.stylefeng.guns.sys.core.util.StringUtils;
import cn.stylefeng.guns.sys.modular.system.entity.User;
import cn.stylefeng.guns.sys.modular.system.model.UserDto;
import cn.stylefeng.guns.sys.modular.system.service.UserService;
import cn.stylefeng.roses.core.base.controller.BaseController;
import cn.stylefeng.roses.core.reqres.response.ErrorResponseData;
import cn.stylefeng.roses.core.reqres.response.ResponseData;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;


/**
 * 用户api
 *
 * @author jwj
 * @Date 2019-07-12 14:20:25
 */
@RestController
@RequestMapping("/gunsApi/account")
@Slf4j
public class AccountApi extends BaseController {

    @Autowired
    private AccountService accountService;

    @Autowired
    private UserService userService;

    @Autowired
    private MoneyLogService moneyLogService;

    @Autowired
    private UserPropertyService userPropertyService;

    @Autowired
    Redishandler0 redishandler0;

    /**
     * 注册用户
     *
     * @param userget-total-teamDto
     * @return
     */
    @PostMapping("/reg")
    public ResponseData reg(UserDto userDto) {
        if (StringUtils.isAnyEmpty(userDto.getAccount(), userDto.getPassword())) {
            return ResponseData.error(500, "账户和密码不能为空");
        }
        if (StringUtils.isEmpty(userDto.getSmsCode())) {
            return ResponseData.error(500, "短信验证码不能为空");
        }
        accountService.reg(userDto);
        return ResponseData.success();
    }

    /**
     * 重置密码
     *
     * @param account
     * @param smsCode
     * @param newPassword
     * @return
     */
    @PostMapping("/restore-password")
    public ResponseData restorePassword(@RequestParam String account, @RequestParam String smsCode, @RequestParam String newPassword) {
        if (StringUtils.isAnyEmpty(account, smsCode, newPassword)) {
            return ResponseData.error(500, "账户和验证码，短信不能为空");
        }
        //验证短信
        boolean smsResult = accountService.invalidSMS(account, smsCode);
        if (!smsResult) {
            return ResponseData.error(500, "验证码错误！");
        }
        return ResponseData.success(accountService.changePassword(account, newPassword));
    }

    /**
     * api登录接口，通过账号密码获取token
     */
    @RequestMapping("/auth-code")
    public Object auth(@RequestParam("username") String username,
                       @RequestParam("code") String code) {


        //获取数据库中的账号密码，准备比对
        User user = userService.getByAccount(username);
        if (user == null) {
            return new ErrorResponseData(500, "账号错误！");
        }
        //验证短信
        boolean smsResult = accountService.invalidSMS(username, code);
        if (!smsResult) {
            return new ErrorResponseData(500, "验证码错误！");
        }

        //封装请求账号密码为shiro可验证的token
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, code);

        String credentials = code;
        String salt = user.getSalt();
        ByteSource credentialsSalt = new Md5Hash(salt);
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
                new ShiroUser(), credentials, credentialsSalt, "");

        //校验用户账号密码
        HashedCredentialsMatcher md5CredentialsMatcher = new HashedCredentialsMatcher();
        md5CredentialsMatcher.setHashAlgorithmName(ShiroKit.hashAlgorithmName);
        md5CredentialsMatcher.setHashIterations(ShiroKit.hashIterations);
        boolean passwordTrueFlag = md5CredentialsMatcher.doCredentialsMatch(
                usernamePasswordToken, simpleAuthenticationInfo);

        if (passwordTrueFlag) {
            JSONObject userProperty = userPropertyService.getPropertyByUser(user.getUserId());
            HashMap<String, Object> result = new HashMap<>();
            result.put("token", JwtTokenUtil.generateToken(String.valueOf(user.getUserId())));
            result.put("account", user.getAccount());
            result.put("userName", user.getName());
            result.put("userId", user.getUserId());
            if (userProperty != null) {
                result.put("gradeId", userProperty.getIntValue("gradeId"));
                result.put("gradeLevel", userProperty.getIntValue("gradeLevel"));
            }
            //实名认证
            result.put("certificationStatus", user.getCertificationStatus());
            result.put("refeeInfo", user.getRefeeInfo());
            String systemUnreadMessageCountStr = redishandler0.getStringValue(Constants.UNREAD_MESSAGE_COUNT_KEY, user.getUserId().toString() + 1);
            String platformUnreadMessageCountStr = redishandler0.getStringValue(Constants.UNREAD_MESSAGE_COUNT_KEY, user.getUserId().toString() + 2);
            Integer systemUnreadMessageCount = StringUtils.isNotEmpty(systemUnreadMessageCountStr) ? Integer.valueOf(systemUnreadMessageCountStr) : 0;
            Integer platformUnreadMessageCount = StringUtils.isNotEmpty(platformUnreadMessageCountStr) ? Integer.valueOf(platformUnreadMessageCountStr) : 0;
            result.put("systemUnreadMessageCount", systemUnreadMessageCount);
            result.put("platformUnreadMessageCount", platformUnreadMessageCount);
            return ResponseData.success(result);
        } else {
            return new ErrorResponseData(500, "账号密码错误！");
        }
    }


    @ApiOperation("获取个人信息")
    @GetMapping("/information")
    public ResponseData information(@RequestParam long userId) {
        return ResponseData.success(accountService.information(userId));
    }

    @ApiOperation("获取个人等级信息")
    @GetMapping("/userGrade")
    public ResponseData getUserGrade(@RequestParam long userId) {
        return ResponseData.success(accountService.getUserGrade(userId));
    }

    @ApiOperation("修改用户昵称")
    @PostMapping("/updateName")
    public ResponseData updateName(@RequestParam long userId, @RequestParam(required = false) String name, @RequestParam(required = false) String headImageUrl) {
        if (accountService.updateName(userId, name, headImageUrl)) {
            return ResponseData.success();
        }
        return ResponseData.error("修改失败");
    }

    @ApiOperation("接收微信消息推送")
    @PostMapping("/messagePush")
    public ResponseData messagePush(@RequestParam long userId, @RequestParam String messagePush) {
        if (accountService.messagePush(userId, messagePush)) {
            return ResponseData.success();
        }
        return ResponseData.error("更新微信消息推送失败");
    }

    @ApiOperation("修改或添加个人微信号")
    @PostMapping("/saveWx")
    public ResponseData saveWxID(@RequestParam long userId, @RequestParam String wxID) {
        if (accountService.saveWxID(userId, wxID)) {
            return ResponseData.success();
        }
        return ResponseData.error("更新微信消息推送失败");
    }

    @ApiOperation("更换手机号")
    @PostMapping("changePhone")
    public ResponseData changePhone(@RequestParam long userId, @RequestParam String oldPhone, @RequestParam String newPhone, @RequestParam String smsCode) {
        if (StringUtils.isAnyBlank(oldPhone, newPhone)) {
            return ResponseData.error(500, "手机号不能为空");
        }
        if (StringUtils.isEmpty(smsCode)) {
            return ResponseData.error(500, "短信验证码不能为空");
        }
        if (accountService.changePhone(userId, oldPhone, newPhone, smsCode)) {
            return ResponseData.success();
        }
        return ResponseData.error("更换手机号失败");
    }

    @ApiOperation("修改密码")
    @PostMapping("changePassword")
    public ResponseData changePassword(@RequestParam long userId, @RequestParam String oldPassword, @RequestParam String newPassword, @RequestParam String repeatPassword) {
        if (StringUtils.isAnyBlank(oldPassword, newPassword, repeatPassword)) {
            return ResponseData.error(500, "密码不能为空");
        }
        if (!newPassword.equals(repeatPassword)) {
            return ResponseData.error(405, "两次输入密码不一致");
        }
        if (accountService.changePassword(userId, oldPassword, newPassword)) {
            return ResponseData.success();
        }
        return ResponseData.error("修改密码失败");
    }

    @ApiOperation("联系我们")
    @GetMapping("contactUs")
    public ResponseData contactUs() {
        return ResponseData.success(accountService.contactUs());
    }

    /**
     * 验证手机号是否存在
     *
     * @param account
     * @return
     */
    @ApiOperation("验证手机号是否存在")
    @GetMapping("account-exist")
    public ResponseData phoneExist(@RequestParam String account) {
        if (StringUtils.isNotEmpty(account)) {
            return ResponseData.error("手机号不能为空");
        }
        /*if (ValidateUtils.isPhone(phone)) {
            return ResponseData.error("手机号已经存在");
        }*/
        Integer userC = userService.count(new QueryWrapper<User>().eq("account", account));
        if (userC > 0) {
            return ResponseData.error("已经存在该手机账号");
        }
        return ResponseData.success();
    }

    /**
     * 发送短信
     *
     * @param phone
     * @param type
     * @return
     */
    @ApiOperation("发送短信")
    @GetMapping("/sendSMS")
    public ResponseData sendSMS(@RequestParam String phone, @RequestParam Integer type) {
        if (StringUtils.isEmpty(phone)) {
            return ResponseData.error("手机号不能为空");
        }
        if (type == null) {
            type = SmsTemplateCode.CHANGE.getCode();
        }
        String temCodeKey = SmsTemplateCode.getDescByCode(type);
        if (StringUtils.isEmpty(temCodeKey)) {
            return ResponseData.error("短信配置信息错误");
        }

        if (type.equals(SmsTemplateCode.REG.getCode())) {
            Integer userC = userService.count(new QueryWrapper<User>().eq("phone", phone));
            if (userC > 0) {
                return ResponseData.error("已经存在该手机账号");
            }
        }
        String temCode = (String) ConstantsContext.getConstntsMap().get(temCodeKey);
        boolean result = accountService.sendSMS(phone, temCode);
        if (result) {
            return ResponseData.success("成功");
        } else {
            return ResponseData.error("发送短信错误");
        }
    }

    /**
     * 验证短信
     *
     * @param phone
     * @param code
     * @return
     */
    @ApiOperation("验证短信")
    @GetMapping("/verify-code")
    public ResponseData verifySmsCode(@RequestParam String phone, @RequestParam String code) {
        if (StringUtils.isEmpty(phone)) {
            return ResponseData.error("手机号不能为空");
        }
        if (StringUtils.isEmpty(code)) {
            return ResponseData.error("验证码不能为空");
        }

        boolean result = accountService.invalidSMS(phone, code);
        if (result) {
            return ResponseData.success("成功");
        } else {
            return ResponseData.error("验证码不正确");
        }
    }

    /**
     * 获取openid
     *
     * @param code 微信code
     * @return openid
     */
    @ApiOperation("获取openid")
    @GetMapping("/openId/{code:.+}")
    public ResponseData getOpenid(@PathVariable("code") String code) {
        return ResponseData.success(accountService.getOpenId(code));

    }

    @ApiOperation("微信用户绑定")
    @PostMapping("/binging/user/info")
    public ResponseData binding(@RequestBody BindingUserInfoDTO bindingUserInfoDTO) {
        if (StringUtils.isEmpty(bindingUserInfoDTO.getPhone())) {
            return ResponseData.error("手机号不能为空");
        }
        if (StringUtils.isEmpty(bindingUserInfoDTO.getPwd())) {
            return ResponseData.error("密码不能为空");
        }
        return ResponseData.success(accountService.binding(bindingUserInfoDTO));
    }

    @ApiOperation("检查用户手机号是否绑定并发送验证码")
    @PostMapping("/check/user")
    public ResponseData checkUserBingStatusAndSendMessage(@RequestParam String phone, @RequestParam String openid) {
        if (StringUtils.isAnyBlank(phone, openid)) {
            return ResponseData.error("参数错误");
        }
        accountService.checkUserBingStatusAndSendMessage(phone, openid);
        return ResponseData.success();
    }

    /**
     * 根据微信获取凭证
     *
     * @param openId 微信
     * @return BingingResultView
     */
    @ApiOperation("根据openid获取用户token")
    @PostMapping("/token/{openId}")
    public ResponseData getAccountTokenWeixin(@PathVariable("openId") String openId) {
        log.info("根据微信获取凭证,请求参数:{}", openId);
        BingingResultView bingingResultView = accountService.getAccountTokenWeixin(openId);
        if (bingingResultView == null) {
            return ResponseData.error("用户还没有绑定");
        } else {
            return ResponseData.success(bingingResultView);
        }
    }

    /**
     * 分页获取我的直推团队
     *
     * @return
     */
    @ApiOperation("分页获取我的直推团队")
    @PostMapping("children-page")
    public ResponseData childrenPage(Page page, UserTeamParam userTeamParam) {
        return ResponseData.success(userPropertyService.getMyPushList(page, userTeamParam));
    }

    /**
     * 获取我的团队人数和收益
     *
     * @return
     */
    @ApiOperation("获取我的团队人数和收益")
    @GetMapping("get-total-team")
    public ResponseData getMyTeam(@RequestParam Long userId) {
        return ResponseData.success(accountService.getMyTeamTotal(userId));
    }


    @ApiOperation("按条件分页查询我的余额及记录")
    @GetMapping("/record")
    public ResponseData record(@RequestHeader(value = "userId") Long userId,
                               Integer type, @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
                               @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
                               String startTime, String endTime) {
        Page page = new Page(pageNo, pageSize);
        List<MoneyLogResult> record = moneyLogService.record(page, userId, new AmountQueryCondition(type, startTime, endTime));
        BigDecimal totalAmount = moneyLogService.totalAmount(userId);
        page.setRecords(record);
        return ResponseData.success(new AmountRecordResult(totalAmount, page));
    }

    /**
     * 获取我的团队人数和收益
     *
     * @return
     */
    @ApiOperation("获取余额明细")
    @GetMapping("amount-detail")
    public ResponseData getAmountDetail(@RequestParam Integer moneyId) {
        return ResponseData.success(accountService.getMoneyDetail(moneyId));
    }


    /**
     * 获取我的推广图片
     *
     * @return
     */
    @ApiOperation("获取我的推广图片")
    @GetMapping("get-refees")
    public ResponseData getRefeeImages(@RequestParam Long userId) {
        return ResponseData.success(accountService.getRefeeImages(userId));
    }

    /**
     * 获取我的推广图片
     *
     * @return
     */
    @ApiOperation("获取我的平台推广图片")
    @GetMapping("get-pt-refees")
    public ResponseData getPTRefeeImages(@RequestParam Long userId) {
        return ResponseData.success(accountService.getPTRefeeImages(userId));
    }
}


